/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2025-07-14 14:09:26
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2025-07-15 15:18:58
 * @FilePath: /NetProjectVideo/source_code/server.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "data_management.hpp"
#include "httplib.h"
#include <cstdio>

namespace aod
{
// 设置：静态资源根目录
#define WWWROOT "./wwwroot"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image"

    TableVideo *tb_video = NULL; // 创建数据库管理对象
    class Server
    {
    private:
        int _port;
        httplib::Server _srv;

    private:
        // 加static，消除类内成员的隐藏参数this指针
        static void Insert(const httplib::Request &req, httplib::Response &rep)
        {
            // 先判断客户端是否上传的数据出错
            if (req.has_file("name") == false || req.has_file("info") == false || req.has_file("video") == false || req.has_file("image") == false)
            {
                rep.status = 400;
                rep.body = R"({result:false,reason:"客户端上传视频格式出错"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }

            // MultipartFormData包含{name,content-type,content,filename}
            httplib::MultipartFormData name = req.get_file_value("name");   // 视频名称
            httplib::MultipartFormData info = req.get_file_value("info");   // 视频简介
            httplib::MultipartFormData video = req.get_file_value("video"); // 视频
            httplib::MultipartFormData image = req.get_file_value("image"); // 视频封面
            // 1、先把req里面的视频信息，提取到数据类型为MultipartFormData里面，再进行访问

            std::string root = WWWROOT; // 多余写一个root,防止写video_path的时候+拼接失败
            std::string video_name = name.content;
            std::string video_info = info.content;

            // 2、设置好实际路径：
            std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
            std::string image_path = root + IMAGE_ROOT + video_info + image.filename;

            // 3、将文件储存到file
            if (FileUtil(video_path).SetConnect(video.content) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"视频文件储存失败"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }

            if (FileUtil(image_path).SetConnect(image.content) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"图片文件储存失败"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
            // 4、以Json::Value的形式，将文件储存到数据库
            Json::Value video_json;
            video_json["name"] = video_name;
            video_json["info"] = video_info;
            // 没有wwwroot就不是真实的存储路径
            video_json["video"] = VIDEO_ROOT + video_name + video.filename; //  /video/你行你上up.mp4
            video_json["image"] = IMAGE_ROOT + video_info + image.filename; //  /image/你行你上up.jpg

            if (tb_video->Insert(video_json) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"视频新增到数据库失败"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
            return;
        }
        static void Delete(const httplib::Request &req, httplib::Response &rep)
        {
            // 1、获取要删除视频的id
            int video_id = std::stoi(req.matches[1]);
            // 2、删除：视频+封面文件
            Json::Value video;
            if (tb_video->Selectone(video_id, &video) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"未找到要删除的视频？"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
            std::string root = WWWROOT;
            std::string video_path = root + video["video"].asString();
            std::string image_path = root + video["image"].asString(); // 加root了，就是实际储存路径
            remove(video_path.c_str());
            remove(image_path.c_str()); // 直接删除

            // 3、删除数据库信息

            if (tb_video->Delete(video_id) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"删除视频失败"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
            return;
        }
        static void Update(const httplib::Request &req, httplib::Response &rep)
        {
            // 1、获取要修改的视频的信息
            // (1)视频id
            int video_id = std::stoi(req.matches[1]);
            // (2)需要修改的内容
            Json::Value video;
            if (JsonUtil::Unserialize(req.body, &video) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"反序列化：解析视频的格式失败！"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
            // 2、修改数据库中目标视频的信息(因为数据库的对象都是Json::Value的数据类型，所以要把要修改的信息str反序列化为Json::Value的数据类型才能传参)、
            if (tb_video->Update(video_id, video) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"修改数据库信息失败！"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
        }

        static void SelectOne(const httplib::Request &req, httplib::Response &rep)
        {
            // 1、获取要查询视频的id
            int video_id = std::stoi(req.matches[1]);
            // 2、在数据库中查询
            Json::Value video;
            if (tb_video->Selectone(video_id, &video) == false)
            {
                rep.status = 500;
                rep.body = R"({result:false,reason:"在数据库查询指定视频失败！"})";
                rep.set_header("Content-Type", "application/json");
                return;
            }
            // 3、组织响应正文：序列化为Json风格的字符串，处理报头信息
            JsonUtil::Serialize(video, &rep.body);
            rep.set_header("Content-Type", "application/json");
        }
        static void SelectAll(const httplib::Request &req, httplib::Response &rep)
        {
            // videos    &   /video?search="关键字"
            // 1、通过设置select_flag分流：(1)是查询所有(2)还是模糊匹配
            bool select_flag = true; // 默认查询所有
            std::string search_key;
            if (req.has_param("search") == true)
            {
                select_flag = false; // 开始进行模糊匹配
                search_key = req.get_param_value("search");
            }
            // 2、在数据库中查询
            Json::Value videos;
            if (select_flag == true)
            {
                if (tb_video->SelectAll(&videos) == false)
                {
                    rep.status = 500;
                    rep.body = R"({result:false,reason:"在数据库查询all视频失败！"})";
                    rep.set_header("Content-Type", "application/json");
                    return;
                }
            }
            else
            {
                if (tb_video->SelectLike(search_key, &videos) == false)
                {
                    rep.status = 500;
                    rep.body = R"({result:false,reason:"在数据库搜索视频失败！"})";
                    rep.set_header("Content-Type", "application/json");
                    return;
                }
            }

            // 3、组织响应正文：序列化为Json风格的字符串，处理报头信息
            JsonUtil::Serialize(videos, &rep.body);
            rep.set_header("Content-Type", "application/json");
        }

    public:
        Server(int port) : _port(port)
        {
        }
        ~Server() {}

        // 总体流程的实现
        bool Module()
        {
            // 1、初始化 数据管理模块，创建指定目录

            tb_video = new TableVideo();
            FileUtil(WWWROOT).CreateDirectory();
            std::string root = WWWROOT;
            std::string video_real_path = root + VIDEO_ROOT; // "./wwwroot/video/"
            FileUtil(video_real_path).CreateDirectory();
            std::string image_real_path = root + IMAGE_ROOT; // "./wwwroot/video/"
            FileUtil(image_real_path).CreateDirectory();

            // 2、搭建http服务器：试运行

            // (1)设置：静态资源根目录
            _srv.set_mount_point("/", WWWROOT);
            // (2)添加：“请求-处理”的映射关系
            _srv.Post("/video", Insert);
            _srv.Delete("/video/(\\d+)", Delete);
            _srv.Put("/video/(\\d+)", Update);
            _srv.Get("/video/(\\d+)", SelectOne);
            _srv.Get("/video", SelectAll);

            // 3、启动服务·器
            _srv.listen("0.0.0.0", _port);
        };
    };
}